             package com.java.diagnostics.visualizer.gc.solarissupport.parser;
             
             import com.java.diagnostics.visualizer.data.DataLevel;
             import com.java.diagnostics.visualizer.data.SourceData;
             import com.java.diagnostics.visualizer.data.StructuredDataBuilder;
             import com.java.diagnostics.visualizer.data.UnstructuredData;
             import com.java.diagnostics.visualizer.data.axes.XAxis;
             import com.java.diagnostics.visualizer.data.axes.XDataAxis;
             import com.java.diagnostics.visualizer.exceptions.GCAndMemoryVisualizerException;
             import com.java.diagnostics.visualizer.factory.DataFactory;
             import com.java.diagnostics.visualizer.factory.SourceDataFactory;
             import com.java.diagnostics.visualizer.gc.solarissupport.util.Messages;
             import com.java.diagnostics.visualizer.impl.factory.LogFactory;
             import com.java.diagnostics.visualizer.parser.vgc.VGCDataManager;
             import com.java.diagnostics.visualizer.parser.vgc.VGCParserPreferenceHelper;
             import com.java.diagnostics.visualizer.parser.vgc.VGCPlainTextParser;
             import com.java.diagnostics.visualizer.parser.vgc.constants.VGCAxes;
             import com.java.diagnostics.visualizer.parser.vgc.constants.VGCGCReasons;
             import com.java.diagnostics.visualizer.parser.vgc.constants.VGCGCScopes;
             import com.java.diagnostics.visualizer.parser.vgc.j926.J926DateConverter;
             import com.java.diagnostics.visualizer.properties.OutputProperties;
             import com.java.diagnostics.visualizer.sources.Source;
             import java.io.BufferedReader;
             import java.io.IOException;
             import java.text.MessageFormat;
             import java.util.HashMap;
             import java.util.HashSet;
             import java.util.Map;
             import java.util.Set;
             import java.util.Stack;
             import java.util.TreeMap;
             import java.util.logging.Level;
             import java.util.logging.Logger;
             import java.util.regex.Matcher;
             import java.util.regex.Pattern;
             
             public class InstanceSunVGCParser
               extends VGCPlainTextParser
             {
               private static final String JVM_INSTANCE = Messages.getString("InstanceSunVGCParser.jvm.instance");
               
               private static final String HEAPORSPACEMAX = Messages.getString("InstanceSunVGCParser.heap.or.space.max");
               
               private static final String HEAPORSPACETOP = Messages.getString("InstanceSunVGCParser.heap.or.space.top");
               
               private static final String HEAPORSPACEBOTTOM = Messages.getString("InstanceSunVGCParser.heap.or.space.bottom");
               
               private static final String CMS_TYPE_PREFIX = "CMS-";
               
               private static final String RESTART_EXPLANATION = Messages.getString("InstanceSunVGCParser.restarts.explanation");
               
               private static final int NURSERY_NAME_TO_INT = VGCGCScopes.nameToInt("scavenger");
               
               private static final int GLOBAL_NAME_TO_INT = VGCGCScopes.nameToInt("global");
               
               private static final String GC_STRING = "GC";
               
               private static final String FULL_GC = "Full GC";
               
               private static final double BYTES_PER_KB = 1024.0D;
               
               private static final double KB_PER_BYTE = 0.0009765625D;
               
               private static final Logger TRACE = LogFactory.getTrace(InstanceSunVGCParser.class);
               
               private static final DataFactory factory = DataFactory.getFactory("VGC");
               
               private static final XAxis GC_NUMBER_AXIS = factory.createXAxis(
                 "VGCAxes.gc.number", VGCAxes.GC_NUMBER, VGCAxes.NUMBER);
               
               private static final Pattern TIMESTAMP_EXPRESSION = Pattern.compile("([0-9]*[\\.,][0-9][0-9][0-9]): \\[([A-z\\-]*)");
               
               private static final Pattern DATESTAMP_EXPRESSION = Pattern.compile("([0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]T[0-9][0-9]:[0-9][0-9]:[0-9][0-9].[0-9][0-9][0-9])");
               
               private static final Pattern PAUSE_EXPRESSION = Pattern.compile(", ([0-9]*[\\.,][0-9]*) secs\\]");
               
               private static final String HEAP_ELEMENT_LESS_COMMA = "([0-9][0-9]*)K->([0-9][0-9]*)K\\(([0-9][0-9]*)K\\)";
               
               private static final String HEAP_ELEMENT = "([0-9][0-9]*)K->([0-9][0-9]*)K\\(([0-9][0-9]*)K\\)[,\\]]";
               
               private static final Pattern FLAT_HEAP_EXPRESSION = Pattern.compile("[^:] ([0-9][0-9]*)K->([0-9][0-9]*)K\\(([0-9][0-9]*)K\\)");
               
               private static final String NURSERIES = "PSYoungGen|ParNew|DefNew";
               
               private static final String TENUREDS = "PSOldGen|Tenured|ParOldGen";
               
               private static final String CMS = "CMS";
               
               private static final Pattern GCS_EXPRESSION = Pattern.compile("\\[(GC|Full GC)");
               private static final Pattern GCS_PATTERN = Pattern.compile("GC|Full GC");
               
               private static final Pattern NURSERY_PATTERN = Pattern.compile("PSYoungGen|ParNew|DefNew");
               
               private static final Pattern TENURED_PATTERN = Pattern.compile("PSOldGen|Tenured|ParOldGen");
               
               private static final String TIMES = ".*\\[Times: user=([0-9][0-9]*\\.[0-9][0-9]*) sys=([0-9][0-9]*\\.[0-9][0-9]*), real=([0-9][0-9]*\\.[0-9][0-9]*) secs\\].*";
               
               private static final Pattern TIMES_PATTERN = Pattern.compile(".*\\[Times: user=([0-9][0-9]*\\.[0-9][0-9]*) sys=([0-9][0-9]*\\.[0-9][0-9]*), real=([0-9][0-9]*\\.[0-9][0-9]*) secs\\].*");
               
               private static final String PRINT_HEAP_AT_GC_BEFORE_HEADER = ".*Heap before GC invocations=([0-9]+) \\(full ([0-9]+)\\):|.*Heap before gc invocations=([0-9]+):";
               
               private static final Pattern PRINT_HEAP_AT_GC_BEFORE_HEADER_PATTERN = Pattern.compile(".*Heap before GC invocations=([0-9]+) \\(full ([0-9]+)\\):|.*Heap before gc invocations=([0-9]+):");
               
               private static final String PRINT_HEAP_AT_GC_AFTER_HEADER = ".*Heap after GC invocations=([0-9]+) \\(full ([0-9]+)\\):|.*Heap after gc invocations=([0-9]+):";
               
               private static final Pattern PRINT_HEAP_AT_GC_AFTER_HEADER_PATTERN = Pattern.compile(".*Heap after GC invocations=([0-9]+) \\(full ([0-9]+)\\):|.*Heap after gc invocations=([0-9]+):");
               
               private static final String PRINT_HEAP_AT_GC_GENERATION_INFO = "(.*)total ([0-9]+)K, used ([0-9]+)K \\[(0x[0-9a-f]+), *(0x[0-9a-f]+), *(0x[0-9a-f]+)\\)";
               
               private static final Pattern PRINT_HEAP_AT_GC_GENERATION_INFO_PATTERN = Pattern.compile("(.*)total ([0-9]+)K, used ([0-9]+)K \\[(0x[0-9a-f]+), *(0x[0-9a-f]+), *(0x[0-9a-f]+)\\)");
               
               private static final String PRINT_HEAP_AT_GC_SPACE_INFO = "(.*space) ([0-9]+)K, +([0-9]+)% used \\[(0x[0-9a-f]+), *(0x[0-9a-f]+), *(0x[0-9a-f]+)(\\)|, *(0x[0-9a-f]+)\\))";
               
               private static final Pattern PRINT_HEAP_AT_GC_SPACE_INFO_PATTERN = Pattern.compile("(.*space) ([0-9]+)K, +([0-9]+)% used \\[(0x[0-9a-f]+), *(0x[0-9a-f]+), *(0x[0-9a-f]+)(\\)|, *(0x[0-9a-f]+)\\))");
               
               private static final String USED_MESSAGE = Messages.getString("SunVGCParser.amount.used");
               
               private static final String SIZE_MESSAGE = Messages.getString("SunVGCParser.total.size");
               
               private static final String BEFORE_MESSAGE = Messages.getString("SunVGCParser.before.collection");
               
               private static final String AFTER_MESSAGE = Messages.getString("SunVGCParser.after.collection");
               
               private static final Pattern ORPHANED_HEAPPREFIX = Pattern.compile(".*\\[(GC|Full GC|PSYoungGen|ParNew|DefNew|PSOldGen|Tenured|ParOldGen|CMS):* *([^0-9]|$)");
               
               private static final Pattern ORPHANED_HEAP_EXPRESSION = Pattern.compile("^:* ([0-9][0-9]*)K->([0-9][0-9]*)K\\(([0-9][0-9]*)K\\)");
               
               private static final Pattern NURSERY_HEAP_EXPRESSION = Pattern.compile("(PSYoungGen|ParNew|DefNew): ([0-9][0-9]*)K->([0-9][0-9]*)K\\(([0-9][0-9]*)K\\)[,\\]]");
               
               private static final Pattern TENURED_HEAP_EXPRESSION = Pattern.compile("(PSOldGen|Tenured|ParOldGen): ([0-9][0-9]*)K->([0-9][0-9]*)K\\(([0-9][0-9]*)K\\)[,\\]]");
               
               private static final Pattern PERMANENT_HEAP_EXPRESSION = Pattern.compile("(PSPermGen|Perm |Perm): ([0-9][0-9]*)K->([0-9][0-9]*)K\\(([0-9][0-9]*)K\\)[,\\]]");
               
               private static final Pattern SYSTEM_GC_EXPRESSION = Pattern.compile("\\[Full GC \\(System\\)");
               
               private static final Pattern EXCLUSIVE_ACCESS_PAUSE_PATTERN = Pattern.compile("Total time for which application threads were stopped: ([0-9]*.[0-9]*) seconds");
               
               private static final Pattern NESTED_GC_PATTERN = Pattern.compile("\\[(GC|Full GC|PSYoungGen|ParNew|DefNew|Tenured).*");
               
               private static final String VERSION = Messages.getString("SunVGCParser.sun.version");
               
               private static final Pattern CMS_INITIAL_MARK_PATTERN = Pattern.compile(".*CMS-initial-mark: ([0-9]+)K\\(([0-9]+)K\\).*");
               
               private static final Pattern CMS_MARK_PATTERN = Pattern.compile(".*CMS-concurrent-mark: ([0-9]+\\.[0-9]+)/([0-9]+\\.[0-9]+) secs.*");
               
               private static final Pattern CMS_PRECLEAN_PATTERN = Pattern.compile(".*CMS-concurrent-preclean: ([0-9]+\\.[0-9]+)/([0-9]+\\.[0-9]+) secs.*");
               
               private static final Pattern CMS_REMARK_PATTERN = Pattern.compile(".*CMS-remark: ([0-9]+)K\\(([0-9]+)K\\).*");
               
               private static final Pattern CMS_SWEEP_PATTERN = Pattern.compile(".*CMS-concurrent-sweep: ([0-9]+\\.[0-9]+)/([0-9]+\\.[0-9]+) secs.*");
               
               private static final Pattern CMS_RESET_PATTERN = Pattern.compile(".*CMS-concurrent-reset: ([0-9]+\\.[0-9]+)/([0-9]+\\.[0-9]+) secs.*");
               
               private static final Pattern CMS_ABORTABLE_PRECLEAN_PATTERN = Pattern.compile(".*CMS-concurrent-abortable-preclean: ([0-9]+\\.[0-9]+)/([0-9]+\\.[0-9]+) secs.*");
               
               private UnstructuredData restartWarning;
               
               private double runningTimestamp = 0.0D;
               
               private boolean hasTimestamps;
               
               private boolean hasDatestamps;
               private boolean neverUsingTimestamps = false;
               
               private boolean hasGenerations;
               
               private Stack<String> lastSeenHeap = new Stack();
               
               private boolean beforeGCInvocation = true;
               private String currentGeneration = null;
               
               private Set<String> heapDetailsFields = new HashSet();
               private Map<String, Double> queuedPoints = new HashMap();
               private Map<String, String> queuedComments = new HashMap();
               
               private Map<String, Map<String, Object>> currentHeapDetails = new TreeMap();
               private StructuredDataBuilder allHeapDetails = factory
                 .createStructuredData(
                 "InstanceSunVGCParser.heap.details", Messages.getString("InstanceSunVGCParser.heap.details"));
               private SunDataManager sunManager;
               
               private class SunDataManager
                 extends VGCDataManager
               {
                 public SunDataManager(Source source, SourceData data, OutputProperties properties)
                 {
                   super(source,data, properties);
                   this.xAxis = null;
                 }
                 
                 private void createNumberAxis() {
                   this.xAxis = InstanceSunVGCParser.GC_NUMBER_AXIS.createDataAxis(this.source, this.properties);
                 }
                 
                 private XDataAxis getXAxis() {
                   return this.xAxis;
                 }
               }
               
               public SourceData parse(Source source, OutputProperties properties)
                 throws GCAndMemoryVisualizerException
               {
                 TRACE.entering(this.className, "parse");
                 this.filterSystemGCs = PLUGIN_PREFERENCES.getFilterSystemGCs();
                 
                 String line = null;
                 try {
                   String variantIdentifier = source.getVariantIdentifier();
                   this.sourceData = 
                     SOURCE_DATA_FACTORY.createSourceData(variantIdentifier);
                   this.sunManager = new SunDataManager(source, this.sourceData, properties);
                   this.dataManager = this.sunManager;
                   BufferedReader reader = source.getSafeBufferedStreamReader();
                   
                   line = reader.readLine();
                   
                   while (line != null)
                   {
                     handleLine(line, reader, properties);
                     
                     line = reader.readLine();
                   }
                   
                   writeOutSourceData();
                   
                   if (!this.currentHeapDetails.isEmpty()) {
                     this.allHeapDetails.put(
                       MessageFormat.format(JVM_INSTANCE, new Object[] {Integer.valueOf(getRestartCount() + 1) }), this.currentHeapDetails);
                   }
                   if (!this.allHeapDetails.isEmpty()) {
                     this.sourceData.addData(this.allHeapDetails, DataLevel.VARIANT);
                   }
                   
                   this.dataManager.ensureExistanceOf("VGCLabels.jvm.restarts");
                   this.dataManager.ensureExistanceOf("VGCLabels.gc.scopes");
                   this.dataManager.ensureExistanceOf("VGCLabels.gc.reasons");
                   this.dataManager.ensureExistanceOf("VGCLabels.nursery.size");
                   this.dataManager
                     .ensureExistanceOf("VGCLabels.pause.times.with.exclusive.access");
                   this.dataManager.ensureExistanceOf("VGCLabels.permanent.heap.size");
                   this.dataManager.ensureExistanceOf("VGCLabels.tenured.heap.size");
                   this.dataManager.ensureExistanceOf("VGCLabels.live.nursery.heap.after.gc");
                   this.dataManager
                     .ensureExistanceOf("VGCLabels.live.nursery.heap.before.gc");
                   this.dataManager
                     .ensureExistanceOf("VGCLabels.live.permanent.heap.after.gc");
                   this.dataManager
                     .ensureExistanceOf("VGCLabels.live.permanent.heap.before.gc");
                   this.dataManager.ensureExistanceOf("VGCLabels.live.tenured.heap.after.gc");
                   this.dataManager
                     .ensureExistanceOf("VGCLabels.live.tenured.heap.before.gc");
                   this.dataManager.complete();
                   
                   reader.close();
                 } catch (IOException e) {
                   TRACE.warning(line);
                   e.printStackTrace();
                   TRACE.log(Level.WARNING, 
                     Messages.getString("SunVGCParser.caught.exception"), e);
                   this.sourceData = null;
                 }
                 
                 TRACE.exiting(this.className, "parse");
                 return this.sourceData;
               }
               
               private void handleLine(String line, BufferedReader reader, OutputProperties properties)
                 throws GCAndMemoryVisualizerException
               {
                 extractTimestamp(line, properties);
                 try
                 {
                   Matcher gcMatcher = GCS_EXPRESSION.matcher(line);
                   boolean isGCOrFullGC = gcMatcher.find();
                   if (isGCOrFullGC) {
                     boolean isFullGC = "Full GC".equals(gcMatcher.group(1));
                     extractReason(line, isFullGC);
                     extractTimes(line);
                   }
                   
                   extractOrphanedHeap(line);
                   extractHeap(line);
                   
                   boolean hasNursery = extractNurseryHeap(line);
                   
                   if (this.hasGenerations) {
                     boolean hasTenured = extractTenuredHeap(line);
                     boolean hasPermanent = extractPermanentHeap(line);
                     extractScope(hasNursery, hasTenured, hasPermanent);
                   }
                   
                   extractLastSeenHeap(line);
                   
                   if (!isGCOrFullGC)
                   {
                     extractExclusiveAccessPause(line);
                   }
                   
                   extractHeapConfig(line);
                   
                   extractCMSInfo(line);
                   
                   extractPause(line);
                 }
                 catch (ArrayIndexOutOfBoundsException e)
                 {
                   TRACE.warning(line + e.toString());
                 }
               }
               
               private void extractLastSeenHeap(String line)
               {
                 Matcher matcher = ORPHANED_HEAPPREFIX.matcher(line);
                 if (matcher.find()) {
                   this.lastSeenHeap.push(matcher.group(1));
                 }
               }
               
               private void extractScope(boolean hasNursery, boolean hasTenured, boolean hasPermanent)
               {
                 if ((hasTenured) || (hasPermanent)) {
                   addDataPoint("VGCLabels.gc.scopes", GLOBAL_NAME_TO_INT);
                 } else if (hasNursery) {
                   addDataPoint("VGCLabels.gc.scopes", NURSERY_NAME_TO_INT);
                 }
               }
               
               private void extractPause(String line)
               {
                 Matcher expression = PAUSE_EXPRESSION.matcher(line);
                 boolean hasPause = expression.find();
                 if (hasPause) {
                   String pauseString = expression.group(1);
                   pauseString = pauseString.replace(',', '.');
                   double pause = Double.parseDouble(pauseString);
                   pause *= 1000.0D;
                   
                   if (this.sunManager.getXAxis() != null) {
                     if (!this.sunManager.getXAxis().isNested()) {
                       addDataPoint(
                         "VGCLabels.pause.times.without.exclusive.access", 
                         pause);
                     }
                     if (TRACE.isLoggable(Level.FINER)) {
                       TRACE.finer("Decrementing nest depth  since there is a pause in line " + 
                         line);
                     }
                     this.sunManager.getXAxis().rollXForward();
                     
                     String newLine = line.substring(expression.start() + 
                       pauseString.length());
                     extractPause(newLine);
                   }
                 }
               }
               
               private void extractExclusiveAccessPause(String line)
               {
                 Matcher exclusiveAccessPauseMatcher = EXCLUSIVE_ACCESS_PAUSE_PATTERN
                   .matcher(line);
                 boolean hasExclusiveAccessPause = exclusiveAccessPauseMatcher.find();
                 if (hasExclusiveAccessPause) {
                   String pauseString = exclusiveAccessPauseMatcher.group(1);
                   double pause = Double.parseDouble(pauseString);
                   pause *= 1000.0D;
                   
                   if (this.sunManager.getXAxis() != null) {
                     if (!this.sunManager.getXAxis().isNested()) {
                       this.sunManager.getXAxis().rollXBackwards();
                     }
                     addDataPoint("VGCLabels.pause.times.with.exclusive.access", pause);
                     this.sunManager.getXAxis().rollXForward();
                   }
                 }
               }
               
               private void extractOrphanedHeap(String line) {
                 if (!this.lastSeenHeap.isEmpty()) {
                   Matcher heapMatcher = ORPHANED_HEAP_EXPRESSION.matcher(line);
                   boolean hasHeap = heapMatcher.find();
                   if (hasHeap)
                   {
                     String heapName = (String)this.lastSeenHeap.pop();
                     String beforeString = heapMatcher.group(1);
                     String afterString = heapMatcher.group(2);
                     String totalString = heapMatcher.group(3);
                     double before = Double.parseDouble(beforeString) / 0.0009765625D;
                     double after = Double.parseDouble(afterString) / 0.0009765625D;
                     double total = Double.parseDouble(totalString) / 0.0009765625D;
                     Matcher flatMatcher = GCS_PATTERN.matcher(heapName);
                     if (flatMatcher.matches()) {
                       addFlatHeapPoints(before, after, total);
                     }
                     else {
                       Matcher nurseryMatcher = NURSERY_PATTERN.matcher(heapName);
                       if (nurseryMatcher.matches()) {
                         addNurseryPoints(before, after, total);
                       } else {
                         Matcher tenuredMatcher = TENURED_PATTERN
                           .matcher(heapName);
                         if (tenuredMatcher.matches()) {
                           addTenuredPoints(before, after, total);
                         }
                       }
                     }
                   }
                 }
               }
               
               private void extractHeap(String line) {
                 Matcher heapMatcher = FLAT_HEAP_EXPRESSION.matcher(line);
                 boolean hasHeap = heapMatcher.find();
                 if (hasHeap) {
                   String beforeString = heapMatcher.group(1);
                   String afterString = heapMatcher.group(2);
                   String totalString = heapMatcher.group(3);
                   double before = Double.parseDouble(beforeString) / 0.0009765625D;
                   double after = Double.parseDouble(afterString) / 0.0009765625D;
                   double total = Double.parseDouble(totalString) / 0.0009765625D;
                   addFlatHeapPoints(before, after, total);
                 }
               }
               
               private void addFlatHeapPoints(double before, double after, double total)
               {
                 if (this.sunManager.getXAxis() != null) {
                   addDataPoint("VGCLabels.live.normal.heap.before.gc", before);
                   addDataPoint("VGCLabels.live.normal.heap.after.gc", after);
                   if (this.dataManager.fieldHasValues("VGCLabels.flat.heap.size")) {
                     addDataPoint("VGCLabels.total.flat.heap.before.gc", 
                       this.dataManager.getLastValue("VGCLabels.flat.heap.size"));
                   } else {
                     addDataPoint("VGCLabels.total.flat.heap.before.gc", total);
                   }
                   addDataPoint("VGCLabels.flat.heap.size", total);
                 }
               }
               
               private boolean extractNurseryHeap(String line) {
                 boolean thisLineHasNursery = false;
                 Matcher heapMatcher = NURSERY_HEAP_EXPRESSION.matcher(line);
                 boolean hasHeap = heapMatcher.find();
                 if (hasHeap) {
                   this.hasGenerations = true;
                   thisLineHasNursery = true;
                   String beforeString = heapMatcher.group(2);
                   String afterString = heapMatcher.group(3);
                   String totalString = heapMatcher.group(4);
                   double before = Double.parseDouble(beforeString) / 0.0009765625D;
                   double after = Double.parseDouble(afterString) / 0.0009765625D;
                   double total = Double.parseDouble(totalString) / 0.0009765625D;
                   addNurseryPoints(before, after, total);
                 }
                 
                 return thisLineHasNursery;
               }
               
               private void addNurseryPoints(double before, double after, double total)
               {
                 addDataPoint("VGCLabels.live.nursery.heap.before.gc", before);
                 addDataPoint("VGCLabels.live.nursery.heap.after.gc", after);
                 if (this.dataManager.fieldHasValues("VGCLabels.nursery.size")) {
                   addDataPoint("VGCLabels.nursery.size.before", 
                     this.dataManager.getLastValue("VGCLabels.nursery.size"));
                 } else {
                   addDataPoint("VGCLabels.nursery.size.before", total);
                 }
                 addDataPoint("VGCLabels.nursery.size", total);
               }
               
               private boolean extractTenuredHeap(String line) {
                 boolean thisLineHasTenured = false;
                 Matcher heapMatcher = TENURED_HEAP_EXPRESSION.matcher(line);
                 boolean hasHeap = heapMatcher.find();
                 if (hasHeap) {
                   thisLineHasTenured = true;
                   String beforeString = heapMatcher.group(2);
                   String afterString = heapMatcher.group(3);
                   String totalString = heapMatcher.group(4);
                   double before = Double.parseDouble(beforeString) / 0.0009765625D;
                   double after = Double.parseDouble(afterString) / 0.0009765625D;
                   double total = Double.parseDouble(totalString) / 0.0009765625D;
                   addTenuredPoints(before, after, total);
                 }
                 
                 return thisLineHasTenured;
               }
               
               private void addTenuredPoints(double before, double after, double total)
               {
                 addDataPoint("VGCLabels.live.tenured.heap.before.gc", before);
                 addDataPoint("VGCLabels.live.tenured.heap.after.gc", after);
                 addDataPoint("VGCLabels.tenured.heap.size", total);
               }
               
               private boolean extractPermanentHeap(String line) {
                 boolean thisLineHasPermanent = false;
                 Matcher heapMatcher = PERMANENT_HEAP_EXPRESSION.matcher(line);
                 boolean hasHeap = heapMatcher.find();
                 if (hasHeap) {
                   thisLineHasPermanent = true;
                   String beforeString = heapMatcher.group(2);
                   String afterString = heapMatcher.group(3);
                   String totalString = heapMatcher.group(4);
                   double before = Double.parseDouble(beforeString) / 0.0009765625D;
                   double after = Double.parseDouble(afterString) / 0.0009765625D;
                   double total = Double.parseDouble(totalString) / 0.0009765625D;
                   addDataPoint("VGCLabels.live.permanent.heap.before.gc", before);
                   addDataPoint("VGCLabels.live.permanent.heap.after.gc", after);
                   addDataPoint("VGCLabels.permanent.heap.size", total);
                 }
                 
                 return thisLineHasPermanent;
               }
               
               private void extractReason(String line, boolean isFullGC)
                  { 
	                int reason;
                 //int reason;
                 if (isFullGC) {
                   Matcher systemGCMatcher = SYSTEM_GC_EXPRESSION.matcher(line);
                   this.isSys = systemGCMatcher.find();
             //            int reason; 
                     if (this.isSys) {
                     reason = VGCGCReasons.SYS_INT;
                   } else {
                     reason = VGCGCReasons.FULL_INT;
                   }
                 } else {
                   reason = VGCGCReasons.AF_INT;
                 }
                 addDataPoint("VGCLabels.gc.reasons", reason);
               }
               
               private void extractTimestamp(String line, OutputProperties properties) throws GCAndMemoryVisualizerException
               {
                 String newLine = null;
                 
                 if (!this.neverUsingTimestamps) {
                   newLine = extractTimeTimestamp(line, properties);
                 }
                 
                 if ((!this.hasTimestamps) && (!this.hasDatestamps)) {
                   newLine = extractGCNumber(line, properties);
                 }
                 if (newLine != null)
                 {
                   extractTimestamp(newLine, properties);
                 }
               }
               
               private String extractGCNumber(String line, OutputProperties properties)
                 throws GCAndMemoryVisualizerException
               {
                 String newLine = null;
                 Matcher nestedGCMatcher = NESTED_GC_PATTERN.matcher(line);
                 if (nestedGCMatcher.find()) {
                   if (this.sunManager.getXAxis() == null) {
                     this.neverUsingTimestamps = true;
                     
                     this.sunManager.createNumberAxis();
                     this.sunManager.getXAxis().rollXForward();
                   }
                   
                   int secondIndex = nestedGCMatcher.end();
                   newLine = line.substring(secondIndex);
                   
                   this.sunManager.getXAxis().rollXBackwards();
                   if (TRACE.isLoggable(Level.FINER))
                   {
                     TRACE.finer("Incrementing nest depth since there is a GC in line " + 
                       line);
                   }
                   
                   boolean isTopLevelElement = GCS_EXPRESSION.matcher(line).find();
                   
                   if ((this.sunManager.getXAxis().isNested()) && (!isTopLevelElement))
                   {
                     this.currentGCNumber -= 1;
                   }
                   setCurrentTimestamp(this.currentGCNumber);
                 }
                 
                 return newLine;
               }
               
               private void extractDatestamp(String line)
               {
                 Matcher dateExpression = DATESTAMP_EXPRESSION.matcher(line);
                 boolean hasDateStamp = dateExpression.find();
                 if (hasDateStamp) {
                   String date = dateExpression.group();
                   double value = J926DateConverter.parseDate(date);
                   
                   if (this.sunManager.getXAxis() == null) {
                     this.sunManager.createXAxis(true);
                   }
                   this.hasDatestamps = true;
                   setCurrentTimestamp(value);
                 }
               }
               
               private String extractTimeTimestamp(String line, OutputProperties properties)
                 throws GCAndMemoryVisualizerException
               {
                 if (this.hasDatestamps) {
                   extractDatestamp(line);
                   return null;
                 }
                 
                 String newLine = null;
                 
                 Matcher dateExpression = DATESTAMP_EXPRESSION.matcher(line);
                 boolean hasDateTimeStamp = dateExpression.find();
                 if (hasDateTimeStamp) {
                   String date = dateExpression.group();
                   double value = J926DateConverter.parseDate(date);
                   
                   if (this.sunManager.getXAxis() == null) {
                     this.sunManager.createXAxis(true);
                   }
                   this.hasDatestamps = true;
                   setCurrentTimestamp(value);
                   newLine = line
                     .substring(dateExpression.start() + date.length());
                   return newLine;
                 }
                 Matcher expression = TIMESTAMP_EXPRESSION.matcher(line);
                 boolean hasTimeStamp = expression.find();
                 
                 if (hasTimeStamp)
                 {
                   String type = expression.group(2);
                   if (type.startsWith("CMS-")) {
                     String stamp = expression.group(1);
                     
                     stamp = stamp.replace(',', '.');
                     double timestamp = Double.parseDouble(stamp) * 
                       1000.0D;
                     if (this.sunManager.getXAxis() == null) {
                       this.sunManager.createXAxis(false);
                     }
                     boolean nested = this.sunManager.getXAxis().isNested();
                     setCurrentTimestamp(timestamp);
                     if (!nested) {
                       this.sunManager.getXAxis().rollXForward();
                     }
                     return null;
                   }
                   if (this.sunManager.getXAxis() == null) {
                     this.sunManager.createXAxis(false);
                     this.sunManager.getXAxis().rollXForward();
                   }
                   this.hasTimestamps = true;
                   this.sunManager.getXAxis().rollXBackwards();
                   if (TRACE.isLoggable(Level.FINER))
                   {
                     TRACE.finer("Incrementing nest depth since there is a timestamp in line " + 
                       line);
                   }
                   String stamp = expression.group(1);
                   
                   stamp = stamp.replace(',', '.');
                   double timestamp = Double.parseDouble(stamp) * 
                     1000.0D;
                   newLine = line.substring(expression.start() + 
                     stamp.length());
                   
                   boolean timestampUnexpectedlyLow = ((timestamp < 0.5D) || (this.runningTimestamp + timestamp < this.previousTimestamp * 0.5D)) && 
                     (this.sunManager.getXAxis().getSequenceUID() > 10);
                   boolean timestampIndicatesRestart = (timestamp == 0.0D) || (timestampUnexpectedlyLow);
                   
                   if ((timestampIndicatesRestart) && (haveTimestamp()))
                   {
                     if ((this.runningTimestamp == -1.0D) || 
                       (this.runningTimestamp + timestamp < this.previousTimestamp)) {
                       this.sunManager.getXAxis().resetNesting();
                     }
                     
                     logRestart();
                   }
                   
                   if ((timestamp != -1.0D) && (!this.neverUsingTimestamps))
                   {
                     if (TRACE.isLoggable(Level.FINE)) {
                       TRACE.fine("Setting current time to " + timestamp + 
                         " + " + this.runningTimestamp + " = " + 
                         timestamp);
                     }
                     
                     if ((timestampIndicatesRestart) && 
                       (this.restartWarning == null)) {
                       this.restartWarning = 
                         factory
                         
                         .createUnstructuredData("VGCLabels.restart.warning", Messages.getString("VGCLabels.restart.warning"), RESTART_EXPLANATION);
                     }
                     
                     setCurrentTimestamp(timestamp);
                   }
                   else if (this.neverUsingTimestamps) {
                     setCurrentTimestamp(this.currentGCNumber);
                   }
                   
                   if (!this.sunManager.getXAxis().isNested())
                   {
                     this.currentGCNumber += 1;
                   }
                 }
                 
                 return newLine;
               }
               
               private void extractTimes(String line)
               {
                 Matcher timesMatcher = TIMES_PATTERN.matcher(line);
                 if (timesMatcher.matches()) {
                   String userTime = timesMatcher.group(1);
                   String sysTime = timesMatcher.group(2);
                   String realTime = timesMatcher.group(3);
                   try {
                     double userTimeMS = Double.parseDouble(userTime);
                     double sysTimeMS = Double.parseDouble(sysTime);
                     double realTimeMS = Double.parseDouble(realTime);
                     addDataPoint("VGCLabels.user.time", userTimeMS);
                     addDataPoint("VGCLabels.sys.time", sysTimeMS);
                     addDataPoint("VGCLabels.real.time", realTimeMS);
                   }
                   catch (NumberFormatException localNumberFormatException) {}
                 }
               }
               
               private String findOrCreateBytesField(String name)
               {
                 if (!this.heapDetailsFields.contains(name)) {
                   this.sunManager.createDynamicBytesFieldWithTable(name);
                   this.heapDetailsFields.add(name);
                 }
                 return name;
               }
               
               private void addHeapDetailsDataPoint(String name, double value, String comment)
               {
                 if (this.beforeGCInvocation)
                 {
                   String keyName = MessageFormat.format(BEFORE_MESSAGE, new Object[] { name });
                   this.queuedPoints.put(keyName, Double.valueOf(value));
                   this.queuedComments.put(keyName, comment);
                 }
                 else {
                   if (this.sunManager.getXAxis() == null) {
                     this.neverUsingTimestamps = true;
                     this.sunManager.createNumberAxis();
                   }
                   this.sunManager.getXAxis().rollXBackwards();
                   for (String fieldName : this.queuedPoints.keySet()) {
                     String commentToAdd = (String)this.queuedComments.get(fieldName);
                     if (commentToAdd != null) {
                       addDataPoint(findOrCreateBytesField(fieldName), 
                         ((Double)this.queuedPoints.get(fieldName)).doubleValue(), comment);
                     } else {
                       addDataPoint(findOrCreateBytesField(fieldName), 
                         ((Double)this.queuedPoints.get(fieldName)).doubleValue());
                     }
                   }
                   
                   this.queuedPoints = new HashMap();
                   this.queuedComments = new HashMap();
                   String fieldName = MessageFormat.format(AFTER_MESSAGE, new Object[] { name });
                   if (comment != null) {
                     addDataPoint(findOrCreateBytesField(fieldName), value, comment);
                   } else {
                     addDataPoint(findOrCreateBytesField(fieldName), value);
                   }
                   this.sunManager.getXAxis().rollXForward();
                 }
               }
               
               private void extractHeapConfig(String line)
               {
                 Matcher beforeHeaderMatcher = PRINT_HEAP_AT_GC_BEFORE_HEADER_PATTERN
                   .matcher(line);
                 if (beforeHeaderMatcher.matches())
                 {
                   this.beforeGCInvocation = true;
                   
                   return;
                 }
                 Matcher afterHeaderMatcher = PRINT_HEAP_AT_GC_AFTER_HEADER_PATTERN
                   .matcher(line);
                 if (afterHeaderMatcher.matches())
                 {
                   this.beforeGCInvocation = false;
                   
                   return;
                 }
                 Matcher generationMatcher = PRINT_HEAP_AT_GC_GENERATION_INFO_PATTERN
                   .matcher(line);
                 if (generationMatcher.matches()) {
                   String generationName = generationMatcher.group(1).trim();
                   this.currentGeneration = generationName;
                   String totalGenerationSize = generationMatcher.group(2);
                   String generationUsed = generationMatcher.group(3);
                   
                   String heapBottom = generationMatcher.group(4);
                   String heapTop = generationMatcher.group(5);
                   String heapMax = generationMatcher.group(6);
                   
                   Map<String, Object> thisHeap = new TreeMap();
                   thisHeap.put(HEAPORSPACEBOTTOM, heapBottom);
                   thisHeap.put(HEAPORSPACETOP, heapTop);
                   thisHeap.put(HEAPORSPACEMAX, heapMax);
                   this.currentHeapDetails.put(this.currentGeneration, thisHeap);
                   
                   String sizeString = MessageFormat.format(SIZE_MESSAGE, new Object[] {
                     generationName });
                   String usedString = MessageFormat.format(USED_MESSAGE, new Object[] {
                     generationName });
                   addHeapDetailsDataPoint(sizeString, 
                     Double.parseDouble(totalGenerationSize) * 
                     1024.0D, null);
                   addHeapDetailsDataPoint(usedString, 
                     Double.parseDouble(generationUsed) * 
                     1024.0D, null);
                   return;
                 }
                 Matcher spaceMatcher = PRINT_HEAP_AT_GC_SPACE_INFO_PATTERN
                   .matcher(line);
                 if (spaceMatcher.matches()) {
                   String spaceName = spaceMatcher.group(1).trim();
                   String totalSpaceSize = spaceMatcher.group(2);
                   String spacePercentUsed = spaceMatcher.group(3);
                   
                   String spaceBottom = spaceMatcher.group(4);
                   String spaceTop = spaceMatcher.group(5);
                   String spaceMax = spaceMatcher.group(6);
                   
                   if (spaceMatcher.group(8) != null)
                   {
                     spaceMax = spaceMatcher.group(8);
                   }
                   
                   Object thisHeapObj = this.currentHeapDetails.get(this.currentGeneration);
                   if ((thisHeapObj != null) && ((thisHeapObj instanceof Map))) {
                     Map<String, String> thisSpace = new TreeMap();
                     thisSpace.put(HEAPORSPACEBOTTOM, spaceBottom);
                     thisSpace.put(HEAPORSPACETOP, spaceTop);
                     thisSpace.put(HEAPORSPACEMAX, spaceMax);
                     
                     Map<String, Object> thisHeap = (Map)thisHeapObj;
                     thisHeap.put(spaceName, thisSpace);
                   }
                   
                   double totalSpaceSizeBytes = Double.parseDouble(totalSpaceSize) * 
                     1024.0D;
                   double fractionUsed = Double.parseDouble(spacePercentUsed) / 100.0D;
                   
                   double usedSpaceSizeBytes = totalSpaceSizeBytes * fractionUsed;
                   String sizeString = MessageFormat.format(SIZE_MESSAGE, new Object[] {
                     this.currentGeneration + " " + spaceName });
                   String usedString = MessageFormat.format(USED_MESSAGE, new Object[] {
                     this.currentGeneration + " " + spaceName });
                   addHeapDetailsDataPoint(sizeString, totalSpaceSizeBytes, null);
                   addHeapDetailsDataPoint(usedString, usedSpaceSizeBytes, null);
                   return;
                 }
               }
               
               private void extractCMSInfo(String line) {
                 if (line.contains("CMS-")) {
                   if (line.contains("CMS-initial-mark:")) {
                     addCMSSpaceData(line, CMS_INITIAL_MARK_PATTERN, 
                       "VGCLabels.cms.heap.used.at.mark.kickoff", 
                       "VGCLabels.cms.heap.size.at.mark.kickoff");
                   } else if (!line.contains("CMS-concurrent-mark-start"))
                   {
                     if (line.contains("CMS-concurrent-mark:")) {
                       addCMSTimeData(line, CMS_MARK_PATTERN, 
                         "VGCLabels.cms.mark.cpu.time", 
                         "VGCLabels.cms.mark.real.time");
                     } else if (!line.contains("CMS-concurrent-preclean-start"))
                     {
                       if (line.contains("CMS-concurrent-preclean:")) {
                         addCMSTimeData(line, CMS_PRECLEAN_PATTERN, 
                           "VGCLabels.cms.preclean.cpu.time", 
                           "VGCLabels.cms.preclean.real.time");
                       } else if (line.contains("CMS-remark:")) {
                         addCMSSpaceData(line, CMS_REMARK_PATTERN, 
                           "VGCLabels.cms.heap.used.at.remark.kickoff", 
                           "VGCLabels.cms.heap.size.at.remark.kickoff");
                       } else if (!line.contains("CMS-concurrent-sweep-start"))
                       {
                         if (line.contains("CMS-concurrent-sweep:")) {
                           addCMSTimeData(line, CMS_SWEEP_PATTERN, 
                             "VGCLabels.cms.sweep.cpu.time", 
                             "VGCLabels.cms.sweep.real.time");
                         } else if (!line.contains("CMS-concurrent-reset-start"))
                         {
                           if (line.contains("CMS-concurrent-reset:")) {
                             addCMSTimeData(line, CMS_RESET_PATTERN, 
                               "VGCLabels.cms.reset.cpu.time", 
                               "VGCLabels.cms.reset.real.time");
                           } else if (!line.contains("CMS-concurrent-abortable-preclean-start"))
                           {
                             if (line.contains("CMS-concurrent-abortable-preclean:")) {
                               addCMSTimeData(line, CMS_ABORTABLE_PRECLEAN_PATTERN, 
                                 "VGCLabels.cms.abortable.preclean.cpu.time", 
                                 "VGCLabels.cms.abortable.preclean.real.time");
                             } else
                               TRACE.warning("Found unknown CMS event: " + line); } } }
                     }
                   }
                 }
               }
               
               private void addCMSTimeData(String line, Pattern pattern, String cpuTimeField, String realTimeField) {
                 Matcher cmsMatcher = pattern.matcher(line);
                 if (cmsMatcher.matches()) {
                   String cmsCPUTime = cmsMatcher.group(1);
                   String cmsRealTime = cmsMatcher.group(2);
                   double cmsCPUTimeMS = Double.parseDouble(cmsCPUTime) * 
                     1000.0D;
                   double cmsRealTimeMS = Double.parseDouble(cmsRealTime) * 
                     1000.0D;
                   boolean nested = this.sunManager.getXAxis().isNested();
                   addDataPoint(cpuTimeField, cmsCPUTimeMS, this.currentComment);
                   addDataPoint(realTimeField, cmsRealTimeMS, this.currentComment);
                   if (!nested) {
                     this.sunManager.getXAxis().rollXForward();
                   }
                 }
               }
               
               private void addCMSSpaceData(String line, Pattern pattern, String usedField, String sizeField)
               {
                 Matcher cmsMatcher = pattern.matcher(line);
                 if (cmsMatcher.matches()) {
                   String cmsUsed = cmsMatcher.group(1);
                   String cmsSize = cmsMatcher.group(2);
                   double cmsUsedBytes = Double.parseDouble(cmsUsed) * 
                     1024.0D;
                   double cmsSizeBytes = Double.parseDouble(cmsSize) * 
                     1024.0D;
                   boolean nested = this.sunManager.getXAxis().isNested();
                   addDataPoint(usedField, cmsUsedBytes, this.currentComment);
                   addDataPoint(sizeField, cmsSizeBytes, this.currentComment);
                   if (!nested) {
                     this.sunManager.getXAxis().rollXForward();
                   }
                 }
               }
               
               protected void addVersion() {
                 UnstructuredData versionData = factory.createUnstructuredData(
                   "VGCLabels.version", Messages.getString("VGCLabels.version"), 
                   VERSION);
                 this.sourceData.addData(versionData, DataLevel.VARIANT);
               }
               
               protected boolean isTimeStampRelative()
               {
                 return true;
               }
               
               protected void logRestart() {
                 this.allHeapDetails.put(
                   MessageFormat.format(JVM_INSTANCE, new Object[] {Integer.valueOf(getRestartCount() + 1) }), this.currentHeapDetails);
                 this.currentHeapDetails = new TreeMap();
                 super.logRestart();
               }
             }


